package java_thinking.unit_18_IO.exercise;

import java_thinking.unit_17.clone.Student;
import java_thinking.unit_18_IO.utils.BeanUtil;

import java.io.*;

/**
 * @Desc:   实现对象的深度克隆
 * @author: cww
 * @DateTime: 2020-03-29 18:04
 */

public class CloneUtil<T> {

    public static <T> T cloneTo(T t) {
        // 将对象装换到输出流
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objOutputStream =null;
        ObjectInputStream objInputStream = null;
        T dist = null;
        try {
            // 具体装饰角色，装饰具体构建角色，ObjectOutputStream 装饰了 ByteArrayOutputStream，
            // 让原始数据流变成了对象输出流，这样可以直接用对象输出流的 writeObject 直接将对象写入字节流中
            objOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            // 将对象写入字节流中
            objOutputStream.writeObject(t);
            objOutputStream.flush();
            // 将流中的数据读入对象输入流
            objInputStream = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
            dist = (T) objInputStream.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (objOutputStream != null) {
                try {
                    objOutputStream.close();
                    objOutputStream = null;
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if (objInputStream != null) {
                try {
                    objInputStream.close();
                    objInputStream = null;
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return dist;
    }

    public static void main(String[] args) {
        Student s1 = new Student();
        Student s2 = BeanUtil.cloneTo(s1);
        System.out.println("s1 == s2 ? : " + (s1 == s2));
    }

    public static <T> T clonTo1(T src) {
        ByteArrayOutputStream arrayOut = new ByteArrayOutputStream();
        ObjectOutputStream out = null;
        ObjectInputStream in = null;
        T drs = null;
        try {
            out = new ObjectOutputStream(arrayOut);
            out.writeObject(src);
            out.flush();
            in = new ObjectInputStream(new ByteArrayInputStream(arrayOut.toByteArray()));
            drs = (T) in.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if(out != null) {
                try {
                    out.close();
                    out = null;
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if(in != null) {
                try {
                    in.close();
                    in = null;
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return drs;
    }

    public <T> T clone(T o){
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = null;
        ObjectInputStream objectInputStream = null;
        T result = null;
        try {
            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(o);
            objectInputStream = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
            result = (T) objectInputStream.readObject();
            return result;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            if (objectOutputStream!=null){
                try {
                    objectOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (objectInputStream!=null){
                try {
                    objectInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }
}
